
#ifndef __audio_synthH__
#define __audio_synthH__

#include "audio_core.h"

namespace WtfAudio {
	/**
	 * Base class for audio synthesizers
	 **/
	class Generator: public Data {
	public:
		typedef float tInternalFormat;

		inline Generator(const WtfEngine::StringPool::Entry& sName)
			: Data(sName) {};

		DATA_OBJECT(Generator, GC_ADDEDSIZE_AUTO(Data, Generator));
	};

	/**
	 * Base class for decorators, which process existing audio signals
	 **/
	class Decorator: public Generator {
	protected:
		Data::tRef mrSource;
	public:
		inline Decorator(const WtfEngine::StringPool::Entry& sName, Data::tRefa rSrc)
			: Generator(sName), mrSource(rSrc) {};

		DATA_OBJECT(Decorator, GC_ADDEDSIZE_AUTO(Generator, Decorator));
	};

	/**
	 * Interface for amplitude functions, which return the amplitude for a sample
	 * at a given time.
	 **/
	class IAmplitudeFunction: public virtual WtfEngine::IGcObject {
	public:
		virtual tScalar getValue(tScalar time, tScalar dt) = 0;

		GC_INTERFACE(IAmplitudeFunction);
	};


	/**
	 * Frequency sequencer interface
	 **/
	class ISequencer: public virtual WtfEngine::IGcObject {
	public:
		virtual tScalar getValue(tScalar time, tScalar dt) = 0;

		GC_INTERFACE(ISequencer);
	};


	/**
	 * This decorator converts internal format audio data to PCM data.
	 **/
	class PcmOutput: public Decorator {
		mutable WtfEngine::NonCopyBuffer<>::tRef mrBuffer;

	public:
		typedef struct PcmOutputCreationOptions {
			tDataType DataFormat;
			unsigned uBitRate;

			PcmOutputCreationOptions();
		} tCreationOptions;

		PcmOutput(const WtfEngine::StringPool::Entry& sName, Data::tRefa rSrc,
			const tCreationOptions& opts);

		virtual bool getData(WtfEngine::NonCopyBuffer<>::tRefa rBuffer);
		virtual void Reset() {
			mrSource->Reset();
		};

		DATA_RECONSTRUCTIBLE(PcmOutput, GC_ADDEDSIZE_AUTO(Decorator, PcmOutput));
	};

	class WaveGenerator: public Generator {
	public:
		typedef struct WaveGeneratorCreationOptions {
			unsigned uOutputRate;
			IAmplitudeFunction::tRef rAmplitudeFunction;

			WaveGeneratorCreationOptions();
		} tCreationOptions;

	protected:
		IAmplitudeFunction::tRef mrAmplitudeFunction;

		tScalar mTime;

	public:
		WaveGenerator(const WtfEngine::StringPool::Entry& sName, const tCreationOptions& opts);
		
		virtual bool getData(WtfEngine::NonCopyBuffer<>::tRefa rBuffer);
		virtual void Reset();

		DATA_RECONSTRUCTIBLE(WaveGenerator, GC_ADDEDSIZE_AUTO(Generator, WaveGenerator));
	};


	/**
	 * Combines audio streams into a single stream (a software mixer).
	 * The output sample rate is the maximum input rate, slower rates
	 * are upscaled.
	 **/
	class Multiplexer: public Generator {
	public:
		typedef std::pair<WtfEngine::NonCopyBuffer<>::tRef, unsigned> tInput;
		typedef std::list<Generator::tRef> tSourceList;
		typedef std::vector<tInput> tInputBufferList;

		class IType: public virtual WtfEngine::IGcObject {
		public:
			virtual void CombineStreams(WtfEngine::NonCopyBuffer<>::tRefa rOutput,
				const tInputBufferList& inputs, unsigned uSamples) = 0;

			GC_INTERFACE(IType);
		};

		class AdditiveType: public IType, public WtfEngine::GcObject {
		public:
			inline AdditiveType(): WtfEngine::GcObject() {};

			void CombineStreams(WtfEngine::NonCopyBuffer<>::tRefa rOutput,
				const tInputBufferList& inputs, unsigned uSamples);

			GC_AUTOSIZE(AdditiveType);
		};

	private:
		IType::tRef mrType;
		tSourceList mSourceList;
		tInputBufferList mInputBuffers;

	public:
		Multiplexer(const WtfEngine::StringPool::Entry& sName, IType::tRefa rType);

		virtual bool getData(WtfEngine::NonCopyBuffer<>::tRefa rBuffer);
		virtual void Reset();

		void AddSource(Generator::tRefa rStream);
		void RemoveSource(Generator::tRefa rStream);

		const tSourceList& getSources() const {
			return mSourceList;
		};

		DATA_RECONSTRUCTIBLE(Multiplexer, GC_ADDEDSIZE_AUTO(Generator, Multiplexer));
	};


	/**** Wave Functions ****/

	class SquareWaveFunction: public IAmplitudeFunction, public WtfEngine::GcObject {
		ISequencer::tRef mrSequencer;

	public:
		inline SquareWaveFunction(ISequencer::tRefa rSeq)
			: WtfEngine::GcObject(), mrSequencer(rSeq) {};

		tScalar getValue(tScalar time, tScalar dt);

		GC_AUTOSIZE(SquareWaveFunction);
	};

	class SineWaveFunction: public IAmplitudeFunction, public WtfEngine::GcObject {
		ISequencer::tRef mrSequencer;

	public:
		inline SineWaveFunction(ISequencer::tRefa rSeq)
			: WtfEngine::GcObject(), mrSequencer(rSeq) {};

		tScalar getValue(tScalar time, tScalar dt);

		GC_AUTOSIZE(SineWaveFunction);
	};

	class SawtoothWaveFunction: public IAmplitudeFunction, public WtfEngine::GcObject {
		ISequencer::tRef mrSequencer;

	public:
		inline SawtoothWaveFunction(ISequencer::tRefa rSeq)
			: WtfEngine::GcObject(), mrSequencer(rSeq) {};

		tScalar getValue(tScalar time, tScalar dt);

		GC_AUTOSIZE(SawtoothWaveFunction);
	};


	/**** Frequency Sequencers ****/

	/**
	 * Provides a constant frequency, which can be set when needed.
	 **/
	class ConstantFrequency: public ISequencer, public WtfEngine::GcObject {
		tScalar mfFrequency;

	public:
		inline ConstantFrequency(): WtfEngine::GcObject() {};
		inline ConstantFrequency(tScalar f): WtfEngine::GcObject(), mfFrequency(f) {};

		inline tScalar getFrequency() const {
			return mfFrequency;
		};
		inline void setFrequency(float f) {
			mfFrequency = f;
		};

		tScalar getValue(tScalar time, tScalar dt) {
			return mfFrequency;
		};

		GC_AUTOSIZE(ConstantFrequency);
	};
};

#endif
